home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / rpc / rpcHistogram.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  7KB  |  276 lines

  1. /*
  2.  * rpcHistogram.c --
  3.  *
  4.  *      Simple histograms of event durations are maintained by the
  5.  *      routines in this module.  The data recorded includes an average of
  6.  *      time samples, and a histogram at some granularity of time
  7.  *      intervals.
  8.  *
  9.  * Copyright (C) 1986 Regents of the University of California
  10.  * All rights reserved.
  11.  */
  12.  
  13. #ifndef lint
  14. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/rpc/rpcHistogram.c,v 9.2 92/07/10 14:42:24 kupfer Exp $ SPRITE (Berkeley)";
  15. #endif /* not lint */
  16.  
  17.  
  18. #include <sprite.h>
  19. #include <stdio.h>
  20. #include <bstring.h>
  21. #include <status.h>
  22. #include <sync.h>
  23. #include <timer.h>
  24. #include <rpcHistogram.h>
  25. #include <stdlib.h>
  26. #include <vm.h>
  27.  
  28. #define LOCKPTR (&histPtr->lock)
  29.  
  30.  
  31. /*
  32.  *----------------------------------------------------------------------
  33.  *
  34.  * Rpc_HistInit --
  35.  *
  36.  *    Initialize the data structure used to keep an empirical time
  37.  *    distribution, or histogram.
  38.  *
  39.  * Results:
  40.  *    A pointer to the data structure, suitable for passing to
  41.  *    Rpc_HistStart and Rpc_HistStop.
  42.  *
  43.  * Side effects:
  44.  *    Allocates memory for the structure.
  45.  *
  46.  *----------------------------------------------------------------------
  47.  */
  48. Rpc_Histogram *
  49. Rpc_HistInit(numBuckets, usecPerBucket)
  50.     int numBuckets;    /* The number of columns in the histogram */
  51.     int usecPerBucket;    /* The time step between columns in the histogram */
  52. {
  53.     register Rpc_Histogram *histPtr;
  54.     register int bound;
  55.     Timer_Ticks startTicks, endTicks;
  56.  
  57.     histPtr = (Rpc_Histogram *)malloc(sizeof(Rpc_Histogram));
  58.     histPtr->numBuckets = numBuckets;
  59.     histPtr->bucket = (int *)malloc(numBuckets * sizeof(int));
  60.     Sync_LockInitDynamic(&histPtr->lock, "Rpc:histPtr->lock");
  61.     histPtr->aveTimePerCall.seconds = 0;
  62.     histPtr->aveTimePerCall.microseconds = 0;
  63.     bzero((Address)&histPtr->totalTime, sizeof(Time));
  64.     histPtr->numCalls = 0;
  65.     /*
  66.      * Truncate the usecPerBucket to a power of two.  This lets the sampling
  67.      * routines use shifts instead of modulo.
  68.      */
  69.     if (usecPerBucket < 2) {
  70.     usecPerBucket = 2;
  71.     }
  72.     histPtr->bucketShift = 0;
  73.     for (bound = 2 ; bound <= usecPerBucket ; bound <<= 1) {
  74.     histPtr->bucketShift++;
  75.     }
  76.     
  77.     histPtr->usecPerBucket = bound >> 1;
  78.     /*
  79.      * Time the cost of calling the histogram sampling routines.
  80.      */
  81.     Timer_GetCurrentTicks(&startTicks);
  82.     for (bound=0 ; bound<10 ; bound++) {
  83.     Time time;
  84.     Rpc_HistStart(histPtr, &time);
  85.     Rpc_HistEnd(histPtr, &time);
  86.     }
  87.     Timer_GetCurrentTicks(&endTicks);
  88.     Timer_SubtractTicks(endTicks, startTicks, &endTicks);
  89.     Timer_TicksToTime(endTicks, &histPtr->overheadTime);
  90.     Time_Divide(histPtr->overheadTime, 10, &histPtr->overheadTime);
  91.     Rpc_HistReset(histPtr);
  92.     return(histPtr);
  93. }
  94.  
  95. /*
  96.  *----------------------------------------------------------------------
  97.  *
  98.  * Rpc_HistReset --
  99.  *
  100.  *    Reset the histograms, so they start fresh for another benchmark.
  101.  *
  102.  * Results:
  103.  *    None.
  104.  *
  105.  * Side effects:
  106.  *    The counters and average are reset.
  107.  *
  108.  *----------------------------------------------------------------------
  109.  */
  110. ENTRY void
  111. Rpc_HistReset(histPtr)
  112.     register Rpc_Histogram *histPtr;
  113. {
  114.     register int i;
  115.  
  116.     LOCK_MONITOR;
  117.  
  118.     histPtr->numCalls = 0;
  119.     bzero((Address)&histPtr->totalTime, sizeof(Timer_Ticks));
  120.     histPtr->aveTimePerCall.seconds = 0;
  121.     histPtr->aveTimePerCall.microseconds = 0;
  122.     histPtr->numHighValues = 0;
  123.     for (i=0 ; i<histPtr->numBuckets ; i++) {
  124.     histPtr->bucket[i] = 0;
  125.     }
  126.  
  127.     UNLOCK_MONITOR;
  128. }
  129.  
  130. /*
  131.  *----------------------------------------------------------------------
  132.  *
  133.  * Rpc_HistStart --
  134.  *
  135.  *    Take a time sample to start a measured interval and update
  136.  *    the number of calls.  On a Sun-2 this costs about 650 microseconds.
  137.  *
  138.  * Results:
  139.  *    None.
  140.  *
  141.  * Side effects:
  142.  *    Take a time sample and count calls.
  143.  *
  144.  *----------------------------------------------------------------------
  145.  */
  146. ENTRY void
  147. Rpc_HistStart(histPtr, timePtr)
  148.     register Rpc_Histogram *histPtr;    /* The histogram */
  149.     register Time *timePtr;        /* Client storage area fro the time
  150.                      * sample */
  151. {
  152.     LOCK_MONITOR;
  153.     Timer_GetRealTimeOfDay(timePtr, (int *)NIL, (Boolean *)NIL);
  154.     histPtr->numCalls++;
  155.     UNLOCK_MONITOR;
  156. }
  157.  
  158. /*
  159.  *----------------------------------------------------------------------
  160.  *
  161.  * Rpc_HistEnd --
  162.  *
  163.  *    Called at the end of an interval, this determines the length of
  164.  *    the interval, keeps a running sum, and updates a counter
  165.  *    in the histogram corresponding to the interval length.
  166.  *
  167.  * Results:
  168.  *    None.
  169.  *
  170.  * Side effects:
  171.  *    Increment a counter in the histogram.
  172.  *
  173.  *----------------------------------------------------------------------
  174.  */
  175. ENTRY void
  176. Rpc_HistEnd(histPtr, timePtr)
  177.     register Rpc_Histogram *histPtr;    /* The histogram */
  178.     register Time *timePtr;        /* Result from Rpc_HistStart */
  179. {
  180.     Time endTime;
  181.     register int index;
  182.     LOCK_MONITOR;
  183.     Timer_GetRealTimeOfDay(&endTime, (int *)NIL, (Boolean *)NIL);
  184.     Time_Subtract(endTime, *timePtr, timePtr);
  185.     /* 
  186.      * If the command took more than about a half hour, we run into the 
  187.      * risk of overflow when we convert seconds to microseconds.  So, treat 
  188.      * anything greater than 2000 seconds as 2000 seconds.
  189.      */
  190.     if (timePtr->seconds > 2000) {
  191.     timePtr->seconds = 2000;
  192.     }
  193.     index = (timePtr->seconds * 1000000 + timePtr->microseconds) >>
  194.         histPtr->bucketShift;
  195.     if (index >= histPtr->numBuckets) {
  196.     histPtr->numHighValues++;
  197.     } else {
  198.     histPtr->bucket[index]++;
  199.     }
  200.     Time_Add(histPtr->totalTime, *timePtr, &histPtr->totalTime);
  201.     UNLOCK_MONITOR;
  202. }
  203.  
  204. /*
  205.  *----------------------------------------------------------------------
  206.  *
  207.  * Rpc_HistDump --
  208.  *
  209.  *    Copy the histogram data structure to the callers buffer.
  210.  *    It is assumed that it is a user space buffer, and that it
  211.  *    is large enough (a lame assumption).
  212.  *
  213.  * Results:
  214.  *    None.
  215.  *
  216.  * Side effects:
  217.  *    The copy.
  218.  *
  219.  *----------------------------------------------------------------------
  220.  */
  221. ENTRY ReturnStatus
  222. Rpc_HistDump(histPtr, buffer)
  223.     register Rpc_Histogram *histPtr;
  224.     register Address buffer;
  225. {
  226.     register ReturnStatus status;
  227.     
  228.     LOCK_MONITOR;
  229.     status = Vm_CopyOut(sizeof(Rpc_Histogram), (Address)histPtr, buffer);
  230.     if (status == SUCCESS) {
  231.     buffer += sizeof(Rpc_Histogram);
  232.     status = Vm_CopyOut(histPtr->numBuckets * sizeof(int),
  233.                 (Address)histPtr->bucket, buffer);
  234.     }
  235.     UNLOCK_MONITOR;
  236.     return(status);
  237. }
  238.  
  239. /*
  240.  *----------------------------------------------------------------------
  241.  *
  242.  * Rpc_HistPrint --
  243.  *
  244.  *    Print the histogram data structure to the console.
  245.  *
  246.  * Results:
  247.  *    None.
  248.  *
  249.  * Side effects:
  250.  *    The copy.
  251.  *
  252.  *----------------------------------------------------------------------
  253.  */
  254. ENTRY void
  255. Rpc_HistPrint(histPtr)
  256.     register Rpc_Histogram *histPtr;
  257. {
  258.     register int i;
  259.     LOCK_MONITOR;
  260.     Time_Divide(histPtr->totalTime, histPtr->numCalls,
  261.                     &histPtr->aveTimePerCall);
  262.     printf("%d Calls,  ave %d.%06d secs each\n",
  263.            histPtr->numCalls, histPtr->aveTimePerCall.seconds,
  264.            histPtr->aveTimePerCall.microseconds);
  265.     for (i=0 ; i<histPtr->numBuckets ; i++) {
  266.     printf("%8d ", i * histPtr->usecPerBucket);
  267.     }
  268.     printf("Overflow\n");
  269.     for (i=0 ; i<histPtr->numBuckets ; i++) {
  270.     printf("%7d  ", histPtr->bucket[i]);
  271.     }
  272.     printf("%d\n", histPtr->numHighValues);
  273.     printf("\n");
  274.     UNLOCK_MONITOR;
  275. }
  276.